//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//********************************************************* 

using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;

namespace Microsoft.TridentWordAddIn.Common
{
    [XmlRoot("Model")]
    public class Model : DomainBase
    {
        private int autoNumberKey = 1;
        private Model previousVersion;

        /// <summary>
        /// Initializes a new instance of the <see cref="Model"/> class.
        /// </summary>
        public Model()
        {
            this.WorkflowAssociations = new SerializableDictionary<int, WorkflowAssociation>();
            this.Workflows = new SerializableDictionary<Guid, Workflow>();
            this.Modules = new SerializableDictionary<Guid, Module>();
        }

        /// <summary>
        /// Gets a value indicating whether [transaction active].
        /// </summary>
        /// <value><c>true</c> if [transaction active]; otherwise, <c>false</c>.</value>
        [XmlIgnore]
        [DoNotClone]
        [DoNotCompare]
        public bool TransactionActive { get; private set; }

        /// <summary>
        /// Gets or sets the auto number key.
        /// </summary>
        /// <value>The auto number key.</value>
        public int AutoNumberKey
        {
            get { return this.autoNumberKey; }
            set { this.autoNumberKey = value; }
        }

        /// <summary>
        /// Gets or sets the workflow associations.
        /// </summary>
        /// <value>The workflow associations.</value>
        [CompareAsDictionary]
        [CloneAsDictionary]
        public SerializableDictionary<int, WorkflowAssociation> WorkflowAssociations { get; set; }

        /// <summary>
        /// Gets or sets the workflows.
        /// </summary>
        /// <value>The workflows.</value>
        [CompareAsDictionary]
        [CloneAsDictionary]
        public SerializableDictionary<Guid, Workflow> Workflows { get; set; }

        /// <summary>
        /// Gets or sets the modules.
        /// </summary>
        /// <value>The modules.</value>
        [CompareAsDictionary]
        [CloneAsDictionary]
        public SerializableDictionary<Guid, Module> Modules { get; set; }

        /// <summary>
        /// Adds the association.
        /// </summary>
        /// <param name="workflowAssociation">The workflow association.</param>
        public void AddAssociation(WorkflowAssociation workflowAssociation)
        {
            if (workflowAssociation.LocalId <= 0)
            {
                workflowAssociation.LocalId = this.autoNumberKey;
                this.autoNumberKey++;
            }

            if (!this.WorkflowAssociations.ContainsKey(workflowAssociation.LocalId))
            {
                this.WorkflowAssociations.Add(workflowAssociation.LocalId, workflowAssociation);
            }
        }

        /// <summary>
        /// Determines whether [is rerun result inserted].
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if [is rerun result inserted]; otherwise, <c>false</c>.
        /// </returns>
        public bool IsRerunResultInserted()
        {
            bool rerunWillBeLost = false;
            foreach (WorkflowAssociation association in WorkflowAssociations.Values)
            {
                if (association.RerunJob.Job.Id != Guid.Empty && !association.RerunJob.ResultInserted && association.RerunJob.IsOutputPresent)
                {
                    rerunWillBeLost = true;
                    break;
                }
            }

            return rerunWillBeLost;
        }

        /// <summary>
        /// Adds the workflow.
        /// </summary>
        /// <param name="workflow">The workflow.</param>
        public void AddWorkflow(Workflow workflow)
        {
            if (!this.Workflows.ContainsKey(workflow.Id))
            {
                this.Workflows.Add(workflow.Id, workflow);
            }
        }

        /// <summary>
        /// Adds the module.
        /// </summary>
        /// <param name="module">The module.</param>
        public void AddModule(Module module)
        {
            if (!this.Modules.ContainsKey(module.Id))
            {
                this.Modules.Add(module.Id, module);
            }
        }             

        /// <summary>
        /// Deletes the association by id.
        /// </summary>
        /// <param name="id">The id.</param>
        public void DeleteAssociationById(int id)
        {
            this.WorkflowAssociations.Remove(id);
        }       

        /// <summary>
        /// Begins the transaction.
        /// </summary>
        public void BeginTransaction()
        {
            this.previousVersion = (Model)this.Clone();
            this.TransactionActive = true;
        }

        /// <summary>
        /// Commits the transaction.
        /// </summary>
        public void CommitTransaction()
        {
            this.TransactionActive = false;
            this.previousVersion = null;
        }

        /// <summary>
        /// Rolls the back transaction.
        /// </summary>
        /// <returns>Model</returns>
        public Model RollbackTransaction()
        {
            if (this.previousVersion != null)
            {
                this.previousVersion.TransactionActive = false;
                return this.previousVersion;
            }

            return this;
        }
    }

    public class ModelDictionary : Dictionary<int, Model>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ModelDictionary"/> class.
        /// </summary>
        public ModelDictionary()
        {
        }
    }
}
